/***************************************************************************
      File Name:  PathHelpers.cs
   File Created:  Wednesday, June 13th 2007
      Copyright:  (C) 2007 by Darko Matesic
          Email:  darko.matesic@yahoo.com
 ***************************************************************************/

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows.Forms;

namespace CallerID.Helpers
{
    public class PathHelpers
    {
        /// <summary>
        /// Returns application path (path always ends with '\')
        /// </summary>
        public static string GetApplicationPath()
        {
            string appPath = Application.StartupPath;
            if(appPath.EndsWith(Path.DirectorySeparatorChar.ToString()) == false) appPath += Path.DirectorySeparatorChar;
            if(appPath.EndsWith("bin" + Path.DirectorySeparatorChar + "Debug" + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase)) appPath = appPath.Substring(0, appPath.Length - 10);
            if(appPath.EndsWith("bin" + Path.DirectorySeparatorChar + "Release" + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase)) appPath = appPath.Substring(0, appPath.Length - 12);
            return appPath;
        }

        /// <summary>
        /// Returns windows path (path always ends with '\')
        /// </summary>
        /// <returns></returns>
        public static string GetWindowsPath()
        {
            string path = Environment.GetEnvironmentVariable("SystemRoot");
            if(path.EndsWith(Path.DirectorySeparatorChar.ToString()) == false) path += Path.DirectorySeparatorChar;
            return path;
        }

        /// <summary>
        /// Checks if specified path is valid (contains valid characters).
        /// </summary>
        public static bool IsPathValid(string path)
        {
            if(path != null && path.Length > 0) {
                return path.IndexOfAny(System.IO.Path.GetInvalidPathChars()) == -1;
            }
            return false;
        }

        /// <summary>
        /// Returns free space for specified drive. Path must start with drive letter and colon (example "C:")
        /// </summary>
        /// <param name="path">path that starts with drive letter and colon</param>
        /// <returns>free space on specified drive/path, -1 when method fails.</returns>
        public static long GetFreeSpace(string path)
        {
            try {
                if(path == null || path.Length < 2 || path[1] != ':') return -1;
                char letter = path.ToUpper()[0];
                if(letter < 'A' || letter > 'Z') return -1;
                foreach(System.IO.DriveInfo drive in System.IO.DriveInfo.GetDrives()) {
                    try {
                        if(drive.Name.ToUpper()[0] == letter) return (drive.IsReady ? drive.AvailableFreeSpace : 0);
                    } catch { }
                }
            } catch { }
            return -1;
        }

        /// <summary>
        /// Returns valid full path from specified path. Returned path always ends with directory separator.
        /// </summary>
        /// <returns>If method fails it returns empty string.</returns>
        public static string GetValidPath(string path)
        {
            if(path != null && path.Length > 0) {
                try {
                    DirectoryInfo di = new DirectoryInfo(path);
                    if(di != null) {
                        path = di.FullName;
                        if(path.EndsWith(Path.DirectorySeparatorChar.ToString()) == false) path += Path.DirectorySeparatorChar;
                        return path;
                    }
                } catch { }
            }
            return "";
        }

        /// <summary>
        /// Returns path part of full path (returned path always ends with directory separator)
        /// </summary>
        public static string GetFilePath(string fullPath)
        {
            string filePath = "";
            try {
                filePath = System.IO.Path.GetDirectoryName(fullPath);
                if(filePath.EndsWith(Path.DirectorySeparatorChar.ToString()) == false) filePath += Path.DirectorySeparatorChar;
            } catch { }
            return filePath;
        }

        /// <summary>
        /// Creates a relative path from one file or folder to another.
        /// </summary>
        /// <param name="fromDirectory">Contains the directory that defines the start of the relative path.</param>
        /// <param name="toPath">Contains the path that defines the endpoint of the relative path.</param>
        /// <returns>The relative path from the start directory to the end path.</returns>
        public static string GetRelativePath(string fromPath, string toPath)
        {
            try {
                fromPath = new DirectoryInfo(fromPath ?? ".").FullName;
                toPath = new DirectoryInfo(toPath ?? ".").FullName;
                if(string.Compare(Path.GetPathRoot(fromPath), Path.GetPathRoot(toPath), true) != 0) return toPath;
                List<string> relativePath = new List<string>();
                string[] fromDirectories = fromPath.Split(Path.DirectorySeparatorChar);
                string[] toDirectories = toPath.Split(Path.DirectorySeparatorChar);
                int length = Math.Min(fromDirectories.Length, toDirectories.Length);
                int lastCommonRoot = -1;
                // find common root
                for(int x = 0; x < length; x++) {
                    if(string.Compare(fromDirectories[x], toDirectories[x], true) != 0) break;
                    lastCommonRoot = x;
                }
                if(lastCommonRoot == -1) return toPath;
                // add relative folders in from path
                for(int x = lastCommonRoot + 1; x < fromDirectories.Length; x++) {
                    if(fromDirectories[x].Length > 0) relativePath.Add("..");
                }
                // add to folders to path
                for(int x = lastCommonRoot + 1; x < toDirectories.Length; x++) {
                    relativePath.Add(toDirectories[x]);
                }
                // return relative path
                return string.Join(Path.DirectorySeparatorChar.ToString(), relativePath.ToArray());
            } catch { }
            return "";
        }

        /// <summary>
        /// Checks if specified directory is empty.
        /// </summary>
        public static bool IsDirectoryEmpty(string path)
        {
            try {
                if(path != null && path.Length > 0 && Directory.Exists(path)) {
                    return (System.IO.Directory.GetDirectories(path).Length + System.IO.Directory.GetFiles(path).Length) == 0;
                }
            } catch { }
            return true;
        }

        /// <summary>
        /// Creates specified directory if it does not exist. Can create multiple sub directories.
        /// </summary>
        /// <returns>True if directory is created successfuly; otherwise, False.</returns>
        public static bool CreateDirectory(string path)
        {
            try {
                path = GetValidPath(path);
                if(path.Length > 0 && Directory.CreateDirectory(path) != null) return true;
            } catch { }
            return false;
        }

        /// <summary>
        /// Returns files in specified path. If path does not exist it returns empty array.
        /// </summary>
        public static string[] GetFiles(string path)
        {
            string[] files = null;
            try {
                if(Directory.Exists(path)) files = Directory.GetFiles(path);
            } catch { }
            return files ?? new string[] { };
        }
    }
}
